//
// Created by WangPeng on 2024/8/15.
//

#include <iostream>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <regex>
#include "rtsp_protocol.h"
#include "rtp_protocol.h"
#include "../socket/udp_sk.h"
#include "../coded_data/h264_file.h"
#include "../coded_data/aac_file.h"

CRtspCommand::CRtspCommand() : CRtspCommand("")
{

}

CRtspCommand::CRtspCommand(const std::string &req)
{

}

static const int server_rtp_port = 55532;
static const int server_rtcp_port = server_rtp_port + 1;

std::string CRtspCommand::response(std::string req_data, const std::string &client_ip)
{
    req_data_ = std::move(req_data);
    std::vector<std::string> items = split_string(req_data_, "\n");
    try
    {
        //m == method u == url v == version
        std::vector<std::string> muv = split_string(items.at(0), " ");

        auto it = std::find_if(items.cbegin(), items.cend(),
                               [](const std::string& item){return std::string::npos != item.find("CSeq:");});
        int cseq = 0;
        if (items.cend() != it)
        {
            cseq = extract_number(*it);
        }

        std::cout << "cseq = " << cseq << std::endl;
        if (std::string::npos != items.at(0).find(OPTION_CMD))
        {
            return handle_option(cseq);
        }
        if (std::string::npos != items.at(0).find(DESC_CMD))
        {
            return handle_desc(cseq, muv.at(1).c_str());
        }
        if (std::string::npos != items.at(0).find(SETUP_CMD))
        {
            auto it_ports = std::find_if(items.cbegin(), items.cend(),
                                   [](const std::string& item){return std::string::npos != item.find("Transport:");});
            std::pair<int, int> ports{-1, -1};
            if (items.cend() != it_ports)
            {
                //first: client rtp port second: client rtcp port
                ports = extract_ports(*it_ports);
            }
            //构建传输RTP数据的UDP接口
            srv_rtp_fd_ = std::make_shared<CUdpSocket>("192.168.3.65", server_rtp_port);
            srv_rtcp_fd_ = std::make_shared<CUdpSocket>("192.168.3.65", server_rtcp_port);
            if(nullptr != srv_rtp_fd_)
            {
                srv_rtp_fd_->init_client_addr(client_ip, ports.first);
            }
            return handle_setup(cseq, ports.first);
        }
        if (std::string::npos != items.at(0).find(PLAY_CMD))
        {
            play_stream_ = true;//接收到播放指令
            return handle_play(cseq);
        }
    }
    catch (const std::out_of_range& e)
    {
        return {};
    }
    return {};
}

std::string CRtspCommand::handle_option(int cseq)
{
    char result[4096] = {0};
    snprintf(result, sizeof(result) - 1, "RTSP/1.0 200 OK\r\n"
                    "CSeq: %d\r\n"
                    "Public: OPTIONS, DESCRIBE, SETUP, PLAY\r\n"
                    "\r\n",
            cseq);
    return result;
}

std::string CRtspCommand::handle_desc(int cseq, const char *url)
{
    char sdp[500] = {0};
    char local_ip[100] = {0};

    sscanf(url, "rtsp://%[^:]:", local_ip);
#if 0
    snprintf(sdp, sizeof(sdp) - 1, "v=0\r\n"
                 "o=- 9%ld 1 IN IP4 %s\r\n"
                 "t=0 0\r\n"
                 "a=control:*\r\n"
                 "m=video 0 RTP/AVP 96\r\n"
                 "a=rtpmap:96 H264/90000\r\n"
                 "a=control:track0\r\n",
            time(nullptr), local_ip);
#else
    snprintf(sdp, sizeof(sdp) - 1, "v=0\r\n"
                                   "o=- 9%ld 1 IN IP4 %s\r\n"
                                   "t=0 0\r\n"
                                   "a=control:*\r\n"
                                   "m=audio 0 RTP/AVP 97\r\n"
                                   "a=rtpmap:97 mpeg4-generic/44100/2\r\n"
                                   "a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1210;\r\n"

                                   //"a=fmtp:97 SizeLength=13;\r\n"
                                   "a=control:track0\r\n",
             time(nullptr), local_ip);
#endif
    char result[4096] = {0};
    snprintf(result, sizeof(result) -1 , "RTSP/1.0 200 OK\r\nCSeq: %d\r\n"
                    "Content-Base: %s\r\n"
                    "Content-type: application/sdp\r\n"
                    "Content-length: %zu\r\n\r\n"
                    "%s",
            cseq,
            url,
            ::strlen(sdp),
            sdp);
    return result;
}

std::string CRtspCommand::handle_setup(int cseq, int client_rtp_port)
{
    char result[4096] = {0};
    snprintf(result, sizeof(result) - 1, "RTSP/1.0 200 OK\r\n"
                    "CSeq: %d\r\n"
                    "Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d\r\n"
                    "Session: 66334873\r\n"
                    "\r\n",
            cseq,
            client_rtp_port,
            client_rtp_port + 1,
            server_rtp_port,
            server_rtcp_port);
    return result;
}

std::string CRtspCommand::handle_play(int cseq)
{
    char result[4096] = {0};
    snprintf(result, sizeof(result) - 1, "RTSP/1.0 200 OK\r\n"
                    "CSeq: %d\r\n"
                    "Range: npt=0.000-\r\n"
                    "Session: 66334873; timeout=10\r\n\r\n",
            cseq);
    return result;
}

std::vector<std::string> CRtspCommand::split_string(const std::string& src, const std::string &delimiter)
{
    std::vector<std::string> tokens;
    size_t start = 0;
    size_t end = 0;

    // 循环找到每个分隔符的位置，并截取子字符串
    while ((end = src.find(delimiter, start)) != std::string::npos)
    {
        tokens.push_back(src.substr(start, end - start));  // 提取子字符串
        start = end + delimiter.length();  // 移动开始位置，跳过分隔符
    }

    // 最后一个子字符串（或者没有分隔符时的整个字符串）
    tokens.push_back(src.substr(start));

    return tokens;
}

int CRtspCommand::extract_number(const std::string &input)
{
    std::istringstream iss(input);
    std::string label;
    int number;

    // 读取 "CSeq:"，忽略
    iss >> label >> number;

    return number;
}

std::pair<int, int> CRtspCommand::extract_ports(const std::string &input)
{
    std::regex regex_pattern("client_port=(\\d+)-(\\d+)");
    std::smatch match;

    if (std::regex_search(input, match, regex_pattern))
    {
        int port1 = std::stoi(match[1].str());
        int port2 = std::stoi(match[2].str());
        return {port1, port2};
    }
    else
    {
        return {-1, -1};
    }
}

void CRtspCommand::loop_play(const std::string &av_stream_file)
{
    if (!play_stream_) return;
    const std::string ext_h264 = ".h264";
    const std::string ext_aac = ".aac";
    if (av_stream_file.size() >= ext_h264.size()
        || av_stream_file.size() >= ext_aac.size())
    {
        if (0 == av_stream_file.compare(av_stream_file.size() - ext_h264.size(), ext_h264.size(), ext_h264))
        {
            CRtpProtocol rtp_trans;
            std::unique_ptr<CAbstractInterface> ptr_stream_h264 = std::make_unique<CH264File>(av_stream_file);
            ptr_stream_h264->play(srv_rtp_fd_.get(), &rtp_trans);
        }
        else if (0 == av_stream_file.compare(av_stream_file.size() - ext_aac.size(), ext_aac.size(), ext_aac))
        {
            CRtpProtocol rtp_trans(0, 0,
                                   0, RTP_VERSION,
                                   RTP_PAYLOAD_TYPE_AAC, 1,
                                   0, 0, 0x32411);
            std::unique_ptr<CAbstractInterface> ptr_stream_aac = std::make_unique<CAACFile>(av_stream_file);
            ptr_stream_aac->play(srv_rtp_fd_.get(), &rtp_trans);
        }
    }
}
